# encoding: utf-8
import datetime, json, time

import pexpect

from app.extensions import log, db
from flask_restplus import Resource, fields
from app.extensions.api import Namespace, abort, http_exceptions
from app.modules.common.utils import DbCommit, checkToken, ComplexEncoder
from app.modules.common.schemas import BaseSchema
from . import parameters, schemas
from .models import Machine
from app.modules.agent.models import Agent
from app.modules.thread.thread import AddThreadTask
from app import app

api = Namespace('machine', description = "实体机")  # pylint: disable=invalid-name


@api.route('/')
class MachineList(Resource):
    @api.parameters(parameters.MachineListParameters())
    @api.response(schemas.MachineListSchema(many = False))
    @checkToken
    def get(self, args, **kwargs):
        """
        实体机列表
        :param args:
        :return:
        """
        log.info("============== start query machine list ==============")
        _id = args['id']
        log.info("============== id is %s ==============" % _id)
        _list = []
        if _id is not None:
            _list = Machine.query.filter_by(id = _id).all()
        else:
            _list = Machine.query.all()

        for _m in _list:
            _result = db.session.execute(
                "select * from agent left join apply_record on agent.ip = apply_record.agent_ip WHERE agent.machine_ip = :machine_ip and agent.is_del='1'",
                {'machine_ip': _m.ip})
            _l = []
            for row in _result:
                _r = json.loads(json.dumps(dict(row), encoding = "UTF-8", ensure_ascii = False, cls = ComplexEncoder))
                _l.append(_r)
            _m.agent_list = _l

        return {'success': True, 'msg': '', 'data': _list}


@api.route('/del')
class MachineDel(Resource):
    @api.parameters(parameters.MachineDelParameters())
    @api.response(BaseSchema(many = False))
    @checkToken
    def get(self, args, **kwargs):
        """
        删除实体机
        :param args:
        :return:
        """
        log.info("============== start del machine ==============")
        _id = args['id']
        log.info("============== id is %s ==============" % _id)
        _machine = Machine.query.filter_by(id = _id).first()
        if _machine is None:
            _msg = '实体机不存在 id:%s' % _id
            log.error('============== %s ==============' % _msg)
            return {'success': False, 'msg': _msg}

        _list = Agent.query.filter_by(machine_ip = _machine.ip).filter_by(is_del = '1').all()
        if len(_list) != 0:
            _msg = '实体机上存在agent,不能删除 id:%s' % _id
            log.error('============== %s ==============' % _msg)
            return {'success': False, 'msg': _msg}

        db.session.delete(_machine)
        return DbCommit()


@api.route('/update')
class MachineUpdate(Resource):
    @api.parameters(parameters.MachineUpdateParameters())
    @api.response(BaseSchema(many = False))
    @checkToken
    def get(self, args, **kwargs):
        """
        修改实体机信息
        :param args:
        :return:
        """
        log.info("============== start update machine ==============")
        _id = args['id']
        _cpus = args['cpus']
        _ram = args['ram']
        _disks = args['disks']
        log.info("============== id is %s ==============" % _id)
        log.info("============== cpus is %s ==============" % _cpus)
        log.info("============== ram is %s ==============" % _ram)
        log.info("============== disks is %s ==============" % _disks)
        _machine = Machine.query.filter_by(id = _id).first()
        if _machine is None:
            _msg = '实体机不存在 id:%s' % _id
            log.error('============== %s ==============' % _msg)
            return {'success': False, 'msg': _msg}

        _machine.cpus = _cpus
        _machine.ram = _ram
        _machine.disks = _disks

        return DbCommit()


@api.route('/add')
class MachineAdd(Resource):
    @api.parameters(parameters.MachineAddParameters())
    @api.response(BaseSchema(many = False))
    @checkToken
    def post(self, args, **kwargs):
        """
        新增实体机信息
        :param args:
        :return:
        """
        log.info("============== start add machine ==============")
        _ip = args['ip']
        _cpus = args['cpus']
        _ram = args['ram']
        _disks = args['disks']
        log.info("============== ip is %s ==============" % _ip)
        log.info("============== cpus is %s ==============" % _cpus)
        log.info("============== ram is %s ==============" % _ram)
        log.info("============== disks is %s ==============" % _disks)
        _machine = Machine.query.filter_by(ip = _ip).first()
        if _machine is not None:
            _msg = '实体机已存在 ip:%s' % _ip
            log.error('============== %s ==============' % _msg)
            return {'success': False, 'msg': _msg}

        _m = Machine(_ip, _cpus, _ram, _disks)
        db.session.add(_m)
        return DbCommit()


@api.route('/startVM')
class StartVM(Resource):
    @api.parameters(parameters.StartVMParameters())
    @api.response(BaseSchema(many = False))
    def get(self, args, **kwargs):
        """
        启动实体机上的虚拟机
        :param args:
        :return:
        """
        log.info("============== start machine vm ==============")
        _ip = args['ip']
        log.info("============== ip is %s ==============" % _ip)
        _machine = Machine.query.filter_by(ip = _ip).first()
        if _machine is None:
            _msg = '实体机不存在 ip:%s' % _ip
            log.error('============== %s ==============' % _msg)
            return {'success': False, 'msg': _msg}
        # 启动线程启动vm
        _agents = Agent.query.filter_by(machine_ip = _ip).filter_by(is_del = '1').all()
        AddThreadTask(startVM, _ip,_agents)
        return {'success': True, 'msg': ''}


def startVM(ip,_agents):
    for _agent in _agents:
        log.info("app.modules.machine.resources.startVM . agent is %s " % _agent.ip)
        if _agent.vm_id is None:
            log.error(log.info("app.modules.machine.resources.startVM . agent  %s's vm_id is none" % _agent.ip))
            continue
        _cmd = 'sshpass -pwinit2015 ssh root@%s "vim-cmd vmsvc/power.on %s"' % (ip, _agent.vm_id)
        output, status = pexpect.run(_cmd, withexitstatus = 1, timeout = 60)
        if status == 0:
            log.info('start vm %s success.' % _agent.ip)
            # 启动轮询查询虚拟机状态
            _is_start = False
            _count = 0
            while not _is_start and _count < 600:
                try:
                    _cmd = 'sshpass -pwinit2015 ssh root@%s "esxcli vm process list |grep %s"' % (ip, _agent.ip)
                    output, status = pexpect.run(_cmd, withexitstatus = 1, timeout = 60)
                    if status == 0:
                        log.info('vm %s start success ' % _agent.ip)
                        _is_start = True
                        break
                    else:
                        pass
                except:
                    pass
                _count = _count + 1
                time.sleep(10)
        else:
            log.error('start vm %s error . cause:%s' % (_agent.ip, output))
            continue
